package mornd.test1;

import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;

/**
 * @author: mornd
 * @dateTime: 2023/5/8 - 19:55
 * 手动重现控制器层抛出异常，spring 如何处理的
 */
public class App {
    public static void main(String[] args) throws Exception {
        ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
        // 设置消息转换器
        resolver.setMessageConverters(Collections.singletonList(
                new MappingJackson2HttpMessageConverter()));

        // 执行一些初始化操作，比如添加参数解析器和返回值处理器
        resolver.afterPropertiesSet();

        /*
            根据 foo()方法找到其所在的类，再查找该类中所有标注 @ExceptionHandler 的方法
         */
        HandlerMethod handlerMethod = new HandlerMethod(new Controller1(), Controller1.class.getMethod("foo"));

        // 测试嵌套异常
        Exception e = new Exception(new RuntimeException(new IOException("custom io异常")));

        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();

        ModelAndView mav = resolver.resolveException(request, response, handlerMethod, e);

        System.out.println(new String(response.getContentAsByteArray(), StandardCharsets.UTF_8));

//        System.out.println(mav.getModel());
//        System.out.println(mav.getViewName());
    }

    static class Controller1 {

        public void  foo() {}

        // 标注在某个 controller 内，表示只处理该类中方法抛出的异常
        @ExceptionHandler
        @ResponseBody
        public Object handle(IOException e, HttpServletRequest request) {
            return new HashMap<String, Object>(2) {{
                put("error", e);
                put("request", request.toString());
            }};
        }
    }

    static class Controller2 {

        public void  foo() {}

        @ExceptionHandler
        public ModelAndView handle2(ArithmeticException e) {
            return new ModelAndView("view1", new HashMap<String, Object>() {{
                put("error", e.getMessage());
            }});
        }

    }
}
